class Integrations::Slack::SendOnSlackService < Base::SendOnChannelService
  pattr_initialize [:message!, :hook!]

  def perform
    # overriding the base class logic since the validations are different in this case.
    # FIXME: for now we will only send messages from widget to slack
    return unless valid_channel_for_slack?
    # we don't want message loop in slack
    return if message.external_source_id_slack.present?
    # we don't want to start slack thread from agent conversation as of now
    return if message.outgoing? && conversation.identifier.blank?

    perform_reply
  end

  private

  def valid_channel_for_slack?
    # slack wouldn't be an ideal interface to reply to tweets, hence disabling that case
    return false if channel.is_a?(Channel::TwitterProfile) && conversation.additional_attributes['type'] == 'tweet'

    true
  end

  def perform_reply
    send_message

    return unless @slack_message

    update_reference_id
    update_external_source_id_slack
  end

  def message_content
    private_indicator = message.private? ? 'private: ' : ''
    if conversation.identifier.present?
      "#{private_indicator}#{message.content}"
    else
      "*Inbox: #{message.inbox.name} [#{message.inbox.inbox_type}]* \n\n #{message.content}"
    end
  end

  def avatar_url(sender)
    sender.try(:avatar_url) || "#{ENV['FRONTEND_URL']}/admin/avatar_square.png"
  end

  def send_message
    post_message if message_content.present?
    upload_file if message.attachments.any?
  rescue Slack::Web::Api::Errors::AccountInactive => e
    Rails.logger.error e
    hook.authorization_error!
    hook.disable if hook.enabled?
  end

  def post_message
    @slack_message = slack_client.chat_postMessage(
      channel: hook.reference_id,
      text: ActionView::Base.full_sanitizer.sanitize(message_content),
      username: sender_name(message.sender),
      thread_ts: conversation.identifier,
      icon_url: avatar_url(message.sender)
    )
  end

  def upload_file
    result = slack_client.files_upload({
      channels: hook.reference_id,
      initial_comment: 'Attached File!',
      thread_ts: conversation.identifier
    }.merge(file_information))
    Rails.logger.info(result)
  end

  def file_type
    File.extname(message.attachments.first.download_url).strip.downcase[1..]
  end

  def file_information
    {
      filename: message.attachments.first.file.filename,
      filetype: file_type,
      content: message.attachments.first.file.download,
      title: message.attachments.first.file.filename
    }
  end

  def sender_name(sender)
    sender.try(:name) ? "#{sender_type(sender)}: #{sender.try(:name)}" : sender_type(sender)
  end

  def sender_type(sender)
    sender.instance_of?(Contact) ? 'Contact' : 'Agent'
  end

  def update_reference_id
    return if conversation.identifier

    conversation.update!(identifier: @slack_message['ts'])
  end

  def update_external_source_id_slack
    return unless @slack_message['message']

    message.update!(external_source_id_slack: "cw-origin-#{@slack_message['message']['ts']}")
  end

  def slack_client
    @slack_client ||= Slack::Web::Client.new(token: hook.access_token)
  end
end
